#include <SERender/Resourses/Shader.h>
#include <SERender/Resourses/Texture.h>
#include <SERender/Resourses/Loader/TextureLoader.h>
#include <SEEdit/Widget/DragDataLoader.h>
#include <SECore/ResourcePayload.h>

namespace SEngine
{
    constexpr float LABLE_OFFSET = 120.0f;

    template<typename T>
    inline void ShaderUniformAttribute(const std::string & name, Material & material, T & type) {}

    template<>
    inline void ShaderUniformAttribute<int>(const std::string & name, Material & material, int & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        int value = 0; 
        if (!material.Get<int>(name)) {
            material.Set<int>(name, value);
        }
        value = material.Get<int>(name).value();
        ImGui::DragInt("", &value);
        material.Set<int>(name, value);
        ImGui::PopID();
        ImGui::Separator();
    }

    template<>
    inline void ShaderUniformAttribute<float>(const std::string & name, Material & material, float & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        float value = 0; 
        if (!material.Get<float>(name)) {
            material.Set<float>(name, value);
        }
        value = material.Get<float>(name).value();
        ImGui::DragFloat("", &value, 0.01f, 0.0f, 1.0f);
        material.Set<float>(name, value);
        ImGui::PopID();
        ImGui::Separator();
    }

    template<>
    inline void ShaderUniformAttribute<glm::vec2>(const std::string & name, Material & material, glm::vec2 & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        glm::vec2 value{1.0f};
        if (!material.Get<glm::vec2>(name)) {
            material.Set<glm::vec2>(name, value);
        }
        value = material.Get<glm::vec2>(name).value();
        ImGui::DragFloat2("", &value.x, 0.01f, 0.0f, 1.0f);
        material.Set<glm::vec2>(name, value);
        ImGui::PopID();
        ImGui::Separator();
    }

    template<>
    inline void ShaderUniformAttribute<glm::vec3>(const std::string & name, Material & material, glm::vec3 & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        glm::vec3 value{1.0f};
        if (!material.Get<glm::vec3>(name)) {
            material.Set<glm::vec3>(name, value);
        }
        value = material.Get<glm::vec3>(name).value();
        ImGui::ColorEdit3("", &value.x);
        material.Set<glm::vec3>(name, value);
        ImGui::PopID();
        ImGui::Separator();
    }

    template<>
    inline void ShaderUniformAttribute<glm::vec4>(const std::string & name, Material & material, glm::vec4 & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        glm::vec4 value{1.0f};
        if (!material.Get<glm::vec4>(name)) {
            material.Set<glm::vec4>(name, value);
        }
        value = material.Get<glm::vec4>(name).value();
        ImGui::ColorEdit4("", &value.x);
        material.Set<glm::vec4>(name, value);
        ImGui::PopID();
        ImGui::Separator();
    }

    inline void ImageAttributeUI(const std::string & name, Material & material, TextureSlot texSlot) {
        ImGui::BeginGroup();
        ImTextureID id = 0;
        if (auto tex = material.Get<Shader::Sampler>(name); tex && tex->texture) {
            id = (ImTextureID)tex->texture->get().GetId();
        }
        auto oldBorderSize = ImGui::GetStyle().ImageBorderSize;
        ImGui::GetStyle().ImageBorderSize = 1.0f;
        ImGui::Image(id, ImVec2(64, 64), ImVec2{0.0f, 1.0f}, ImVec2{1.0f, 0.0f});
        ImGui::GetStyle().ImageBorderSize = oldBorderSize;
        if (ImGui::BeginDragDropTarget()) {
            if (auto assetsPayload = ImGui::AcceptDragDropPayload("TEXTURE"); assetsPayload && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
                auto assetsElem = (AssetsElem*)assetsPayload->Data;
                material.Set(name, Shader::Sampler{Manager::GetInstance().Get<Texture>(assetsElem->rPath).value().Value(), texSlot, assetsElem->rPath});
            }
            ImGui::EndDragDropTarget();
        }
        ImGui::EndGroup();
    }

    template<>
    inline void ShaderUniformAttribute<Shader::Sampler>(const std::string & name, Material & material, Shader::Sampler & type) {
        ImGui::PushID(name.c_str());
        ImGui::Text((name + ": ").c_str());
        ImGui::SameLine(LABLE_OFFSET);
        ImageAttributeUI(name, material, type.id);
        ImGui::SameLine();
        if (ImGui::Button("Clear")) {
            material.Remove(name);
        }
        ImGui::PopID();
        ImGui::Separator();
    }

} // namespace SEngine
